#include "serialport/qscom.h"
#include <QDebug>
#include <QObject>
#include <QSerialPortInfo>

qscoms::qscoms(QObject *parent) : QObject(parent)
{
    reflush();
}

qscoms::~qscoms()
{
    spsInfo.clear();
    clear();
}

QList<QSerialPortInfo> &qscoms::reflush()
{
    spsInfo.clear();
    spsInfo = QSerialPortInfo::availablePorts();
    return spsInfo;
}

void qscoms::clear()
{
    for (auto &sp : sps) {
        if (sp.sp) {
            sp.sp->close();
            delete sp.sp;
        }
    }
    sps.clear();
}

qscoms::qscomsRet qscoms::open(const QString &name, const PortConfig &pc)
{
    QSerialPortInfo *spInfo;
    if ((spInfo = isValid(name)) == nullptr) {
        return ERROR_NO_FAOUND;
    }
    Sph sp;
    sp.info = *spInfo;
    sp.sp   = new qscom(name, this);
    sp.sp->setBaudRate(pc.baudRate);
    sp.sp->setDataBits(pc.dataBits);
    sp.sp->setStopBits(pc.stopBits);
    sp.sp->setParity(pc.parity);
    sp.sp->setFlowControl(pc.flowCtrl);
    if (!sp.sp->open(qscom::ReadWrite)) {
        delete sp.sp;
        return ERROR_OPEN_FAILED;
    }

    qDebug() << "open " << name << " success";
    QObject::connect(sp.sp, &qscom::sigReadyRead, this, &qscoms::slotReadyRead);
    sp.recBuf = "";
    sps.insert(name, sp);
    return SUCCESS;
}

qscoms::qscomsRet qscoms::close(const QString &name)
{
    if (isValid(name) == nullptr || !sps.contains(name)) {
        return ERROR_NO_FAOUND;
    }
    qDebug() << "close " << name << " success";
    if (!isOpen(name)) {
        return SUCCESS;
    }
    Sph &sp = sps[name];
    if (sp.sp) {
        QObject::disconnect(sp.sp, &qscom::sigReadyRead, this, &qscoms::slotReadyRead);
        sp.sp->close();
        delete sp.sp;
    }
    sps.remove(name);
    return SUCCESS;
}

QSerialPortInfo *qscoms::isValid(const QString &name)
{
    for (auto &spInfo : spsInfo) {
        if (name == spInfo.portName()) {
            return &spInfo;
        }
    }
    return nullptr;
}

bool qscoms::isOpen(const QString &name)
{
    if (isValid(name) == nullptr || !sps.contains(name)) {
        return false;
    }
    Sph &sp = sps[name];
    if (sp.sp) {
        return sp.sp->isOpen();
    }
    return false;
}

qscoms::qscomsRet qscoms::send(const QString &name, const QString &data)
{
    if (isValid(name) == nullptr || !sps.contains(name)) {
        return ERROR_NO_FAOUND;
    }
    Sph &sp = sps[name];
    if (sp.sp) {
        if (sp.sp->write(data.toStdString().c_str()) <= 0) {
            return ERROR_WRITE_FAILED;
        }
        return SUCCESS;
    }
    return ERROR_NO_FAOUND;
}

void qscom::slotReadyRead()
{
//    qDebug() << "slotReadyRead";
    emit sigReadyRead(*this);
}

void qscoms::slotReadyRead(qscom &sp)
{
//    qDebug() << "slotReadyRead";
    QByteArray dataBytes = sp.readAll();
    QString &data        = sps[sp.portName()].recBuf;
    data += dataBytes;

    if (sps[sp.portName()].cached) {
        int size = data.toStdString().length();
        if (size > 0) {
            char chEnd = data.toStdString().at(size - 1);
            if ( ((size > 0 && (chEnd == '\r' || chEnd == '\n' || chEnd == '\0')) )
                || size > 512) {
                emit sigSpDataReceive(sp.portName(), data);
                data.clear();
            }
        }
    } else {
        emit sigSpDataReceive(sp.portName(), data);
        data.clear();
    }
}

void qscoms::setCached(const QString &name, bool cached)
{
    if (isValid(name) == nullptr || !sps.contains(name)) {
        return ;
    }
    sps[name].cached = cached;
}
